﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Packets;
using MQTTnet.Protocol;

namespace Yunwei
{
    public partial class FrmMqtt : Form
    {
        private IMqttClient mqttClient = null;
        public bool isReconnect = false;
        string Clientid = "00000000";
        int totalcount = 0;//发送计数
        int recvcount = 0;//接收计数
        public bool CleanSession = true;
        public FrmMqtt()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {



            cmbPubQOS.SelectedIndex = 0;
            cmbSubQOS.SelectedIndex = 0;
            Clientid = Tbid.Text;
            Tbid.Text = Clientid;
            CleanSession = CHBsession.Checked;


        }
       
        /// <summary>
        /// 连接按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConn_Click(object sender, EventArgs e)
        {
          
            Tbid.Enabled = false;
            TBIP.Enabled = false;
            tbPort.Enabled = false;
            tbpwd.Enabled = false;
            tbUserName.Enabled = false;
            CHBsession.Enabled = false;
            CleanSession = CHBsession.Checked;
            //isReconnect = true;
            Task.Run(async () => { await ConnectMqttServerAsync(); });

           

        }

        public IMqttClientOptions option()
        {
            MqttApplicationMessage mqttApplicationMessage = new MqttApplicationMessage();
            mqttApplicationMessage.Retain = false;
            mqttApplicationMessage.QualityOfServiceLevel = 0;

            //连接到服务器前，获取所需要的MqttClientTcpOptions 对象的信息
            var options = new MqttClientOptionsBuilder()
                .WithClientId(Tbid.Text)
                .WithTcpServer(TBIP.Text, Convert.ToInt32(tbPort.Text))
                .WithCredentials(tbUserName.Text, tbpwd.Text)
                //.WithTls()//服务器端没有启用加密协议，这里用tls的会提示协议异常
                //.WithCleanSession(false)
                .WithCommunicationTimeout(TimeSpan.FromMilliseconds(120000))
                .WithKeepAlivePeriod(TimeSpan.FromMilliseconds(60000))
                .WithCleanSession(CleanSession)
                //.WithCleanSession(true)
                //.WithWillMessage(mqttApplicationMessage)
                .Build();
            return options;
        }
        /// <summary>
        /// 断开连接按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btndisconn_Click(object sender, EventArgs e)
        {
           
            Tbid.Enabled = true;
            TBIP.Enabled = true;
            tbPort.Enabled = true;
            tbpwd.Enabled = true;
            tbUserName.Enabled = true;
            CHBsession.Enabled = true;
            isReconnect = false;
            Task.Run(async () => { await mqttClient.DisconnectAsync(); });
           
        }

        /// <summary>
        /// （1）客户端连接服务器
        /// </summary>
        /// <returns></returns>
        private async Task ConnectMqttServerAsync()
        {

            if (isReconnect)
            {
                MessageBox.Show("设备已经连接到服务器，请勿重复连接！");
                return;
            }
            if (mqttClient == null)
            {
                //实例化 创建客户端对象
                var Factory = new MqttFactory();
                mqttClient = Factory.CreateMqttClient();

                mqttClient.UseConnectedHandler(MqttClient_Connected);
                mqttClient.UseDisconnectedHandler(MqttClient_DisConnected);
                mqttClient.UseApplicationMessageReceivedHandler(MqttClient_ApplicationMessageReceived);
            }
            try
            {

                //调用异步方法连接到服务端

                await mqttClient.ConnectAsync(option());//.ConnectAsync(option());
                isReconnect = true;
            }
            catch (Exception ex)
            {
                Invoke(new Action(() =>
                    {
                        txtReceiveMessage.AppendText($">> [{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}]" +"：   mqtt客户端连接失败" + Environment.NewLine);
                        Tbid.Enabled = true;
                        TBIP.Enabled = true;
                        tbPort.Enabled = true;
                        tbpwd.Enabled = true;
                        tbUserName.Enabled = true;
                        CHBsession.Enabled = true;

                    }));

            }

        }
        private async Task MqttClient_DisConnected(MqttClientDisconnectedEventArgs arg)
        {
            Invoke(new Action(() =>
            {
                //txtReceiveMessage.Clear();
                DateTime curTime = new DateTime();
                curTime = DateTime.Now;
                txtReceiveMessage.AppendText($">> [{curTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}]");
                txtReceiveMessage.AppendText($">>设备已断开MQTT连接！" + Environment.NewLine);
            }));
        }
        private async Task MqttClient_Connected(MqttClientConnectedEventArgs arg)
        {
            Invoke((new Action(() =>
            {
                //txtReceiveMessage.Clear();
                txtReceiveMessage.AppendText($">> [{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}]"+ ":   已连接到MQTT服务器！" + Environment.NewLine);
            })));
        }

        //定义一个缓存存放收到的信息  只存实时上报和上报历史数据0201 0203两个命令
     
        Dictionary<int, string> dicDataRecv = new Dictionary<int, string>();
        private async Task MqttClient_ApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
        {
            int count = this.txtReceiveMessage.Lines.GetUpperBound(0);
            if (count > 1000)
            {
                Invoke(new Action(() =>
                {
                    txtReceiveMessage.Clear();
                }));
            }
            //当收到字符数为1亿是，计数清零
            if (recvcount > Math.Pow(10, 8))
            {
                recvcount = 0;
            }
            Invoke(new Action(() =>
            {
                txtReceiveMessage.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")+ ":     " + $"{"### 收到的信息 ###"}{Environment.NewLine}");
            }));
            Invoke(new Action(() =>
            {
                txtReceiveMessage.AppendText($">>主题={e.ApplicationMessage.Topic}{Environment.NewLine} ");
            }));
            Invoke(new Action(() =>
            {
                byte[] PayloadByte = e.ApplicationMessage.Payload;
                if (PayloadByte.Length > 5)
                {
                    if (PayloadByte[2] == PayloadByte.Length - 3 && PayloadByte[0] == 4)
                    {
                        string str = Encoding.UTF8.GetString(PayloadByte);
                        string Payloadtxt = str.Substring(2);
                        recvcount += str.Length;
                        tbrecvnum.Text = "接收：" + recvcount;
                        txtReceiveMessage.AppendText($">>内容={Payloadtxt}{Environment.NewLine}");
                        txtReceiveMessage.AppendText($">>服务质量等级={e.ApplicationMessage.QualityOfServiceLevel}{Environment.NewLine}");
                    }
                    else
                    {
                        recvcount += Encoding.UTF8.GetString(PayloadByte).Length;
                        tbrecvnum.Text = "接收：" + recvcount;
                        txtReceiveMessage.AppendText($">>内容={Encoding.UTF8.GetString(PayloadByte)}{Environment.NewLine}");
                        txtReceiveMessage.AppendText($">>服务质量等级={e.ApplicationMessage.QualityOfServiceLevel}{Environment.NewLine}");
                    }
                }
                else
                {
                    recvcount += Encoding.UTF8.GetString(PayloadByte).Length;
                    tbrecvnum.Text = "接收：" + recvcount;
                    txtReceiveMessage.AppendText($">>内容={Encoding.UTF8.GetString(PayloadByte)}{Environment.NewLine}");
                    txtReceiveMessage.AppendText($">>服务质量等级={e.ApplicationMessage.QualityOfServiceLevel}{Environment.NewLine}");
                }

                string zz = "";
                for (int i = 0; i < PayloadByte.Length; i++)
                {
                    zz += PayloadByte[i] + " ";
                }

                string[] strby = zz.Split(' ');
                string aaaa = "";
                byte[] bbb = new byte[strby.Length];
                for (int i = 0; i < strby.Length - 1; i++)
                {
                    bbb[i] = Convert.ToByte(strby[i]);
                    if (Convert.ToInt32(strby[i]) < 16)
                    {
                        aaaa += "0" + Convert.ToString(Convert.ToInt32(strby[i]), 16) + " ";
                    }
                    else
                    {
                        aaaa += Convert.ToString(Convert.ToInt32(strby[i]), 16) + " ";
                    }
                }
                //txtReceiveMessage.AppendText(aaaa + "\r\n");
            }));
        }
       
        /// <summary>
        /// 订阅按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private  async void btnSubscribe_Click(object sender, EventArgs e)
        {
            if (mqttClient == null)
            {
                MessageBox.Show("设备未连接！");
                return;
            }
            if (mqttClient.IsConnected)
            {
                await Subscribe();
                label4.Visible = false;
                cmbSubQOS.Visible = false;
            }
           
        }
        /// <summary>
        /// 订阅
        /// </summary>
        /// <returns></returns>
        private async Task Subscribe()
        {
            try
            {
                string subtopic = tbSubTopic.Text;
               
                if (string.IsNullOrEmpty(subtopic))
                {
                    MessageBox.Show("订阅主题不能为空！");
                    return;
                }
                if (!isReconnect)
                {
                    MessageBox.Show("客户端未与服务器端连接!");
                    return;
                }
                //QOS 设置
                string QOS = cmbSubQOS.Text;

                var QOSset = MqttQualityOfServiceLevel.AtLeastOnce;
                switch (QOS)
                {
                    case "0":
                        QOSset = MqttQualityOfServiceLevel.AtMostOnce;
                        break;
                    case "1":
                        QOSset = MqttQualityOfServiceLevel.AtLeastOnce;
                        break;
                    case "2":
                        QOSset = MqttQualityOfServiceLevel.ExactlyOnce;
                        break;
                }

                await mqttClient.SubscribeAsync(new TopicFilterBuilder()
                    .WithTopic(subtopic)
                    .WithQualityOfServiceLevel(QOSset)
            
                    .Build()
                    );
                Invoke(new Action(() =>
                {
                    txtReceiveMessage.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + ":     " + $"已订阅[{subtopic}]主题{Environment.NewLine}");
                }));
            }
            catch (Exception e)
            {
                //MessageBox.Show("1");
            }
        }
        /// <summary>
        /// 发布按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnPublish_Click(object sender, EventArgs e)
        {
            if (mqttClient==null)
            {
                MessageBox.Show("设备未连接！");
                return;
            }
            if (mqttClient.IsConnected)
            {
                if (ckbsend.Checked)
                {
                    if (!IsNumbers(textBox4.Text))
                    {
                        MessageBox.Show("请输入发送数据间隔时间！");
                        return;
                    }
                    else
                    {
                        timer2.Interval = Convert.ToInt32(textBox4.Text);
                    }
                }

                await Publish();
                timer2.Enabled = ckbsend.Checked;
                label6.Visible = false;
                cmbPubQOS.Visible = false;
            }
            else
            {
                MessageBox.Show("设备未连接！");
                return;
            }
        }

        //判断是否能转换为数字
        public static bool IsNumbers(string s)
        {
            try
            {
                double d = Convert.ToDouble(s);
            }
            catch
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 发布
        /// </summary>
        /// <returns></returns>
        private async Task Publish()
        {
            try
            {
                //当收到字符数为1亿是，计数清零
                if (totalcount>Math.Pow(10,8))
                {
                    totalcount = 0;
                }
                string topic = tbPubtopic.Text;
                
                if (!isReconnect)
                {
                    MessageBox.Show("客户端未与服务器端连接!");
                    return;
                }
                if (string.IsNullOrEmpty(topic))
                {
                    MessageBox.Show("发布标题不能为空");
                    return;
                }
               
                string content = tbContent.Text;
                
                //QOS 设置
                string QOS = cmbPubQOS.Text;
                var QOSset = MqttQualityOfServiceLevel.AtLeastOnce;
                switch (QOS)
                {
                    case "0":
                        QOSset = MqttQualityOfServiceLevel.AtMostOnce;
                        break;
                    case "1":
                        QOSset = MqttQualityOfServiceLevel.AtLeastOnce;
                        break;
                    case "2":
                        QOSset = MqttQualityOfServiceLevel.ExactlyOnce;
                        break;
                }
                //发布信息的
                await mqttClient.PublishAsync(new MqttApplicationMessageBuilder()
                    .WithTopic(topic)
                    
                    .WithPayload(content)
                    .WithQualityOfServiceLevel(QOSset)
                    .WithRetainFlag(false)
                    .Build()
                    );
                totalcount += content.Length;
                Invoke(new Action(() =>
                {
                    tbsendnum.Text = "发送：" + totalcount; 
                    txtReceiveMessage.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + ":     " + $"已发布[{topic}]主题的信息{Environment.NewLine}");
                }));
            }
            catch (Exception ex)
            {
               var options = new MqttClientOptionsBuilder()
                    .WithClientId(Tbid.Text)
                    .WithTcpServer(TBIP.Text, Convert.ToInt32(tbPort.Text))
                    .WithCredentials(tbUserName.Text, tbpwd.Text)
                    //.WithTls()//服务器端没有启用加密协议，这里用tls的会提示协议异常
                    .WithCleanSession(CleanSession)
                    //.WithCleanSession(true)
                    .Build();
                //MessageBox.Show("2");
            }
        }
        /// <summary>
        /// 清空消息展示区按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnclear_Click(object sender, EventArgs e)
        {
            txtReceiveMessage.Clear();
        }
        /// <summary>
        /// 取消订阅按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnUnSubscribe_Click(object sender, EventArgs e)
        {
            if (mqttClient == null)
            {
                MessageBox.Show("设备未连接！");
                return;
            }
            if (mqttClient.IsConnected)
            {
                string subtopic = tbSubTopic.Text;
                Task.Run(async () => { await mqttClient.UnsubscribeAsync(subtopic); });
                txtReceiveMessage.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") +":     "+ $"已取消订阅[{subtopic}]主题{Environment.NewLine}");
            }
        }

        #region 八位数随机码

        private static char[] constant = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

        public static string GenerateRandomNumber(int Length)
        {
            System.Text.StringBuilder newRandom = new System.Text.StringBuilder(10);
            Random rd = new Random();
            for (int i = 0; i < Length; i++)
            {
                newRandom.Append(constant[rd.Next(10)]);
            }
            return newRandom.ToString();
          
        }
        #endregion

        #region  判断ip
        public bool IsIp(string value)
        {
            Regex r = new Regex(@"^((25[0-5]|2[0-4]\d|(1\d|[1-9])?\d)\.){3}(25[0-5]|2[0-4]\d|(1\d|[1-9])?\d)$");
            return r.IsMatch(value);

        }
        #endregion
        #region 关闭窗体
        /// <summary>
        /// 关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            //关闭MQTT连接
            Task.Run(async () => { await mqttClient.DisconnectAsync(); });
            Application.Exit();
            
        }
        #endregion

        #region 16进制byte转成16进制字符表示
        public static string ToHexString(byte[] bytes) // 0xae00cf => "AE00CF "

        {
            string hexString = string.Empty;

            if (bytes != null)

            {

                StringBuilder strB = new StringBuilder();

                for (int i = 0; i < bytes.Length; i++)

                {

                    strB.Append(bytes[i].ToString("X2"));

                }

                hexString = strB.ToString();

            }
            return hexString;

        }
        #endregion

        private void timer1_Tick(object sender, EventArgs e)
        {

            timer1.Interval = 1000 * 10;
            timer1.Enabled = true;
             //&& !mqttClient.IsConnected
            if (isReconnect && !mqttClient.IsConnected)
            {
                //启动mqtt,连接server
                Task.Run(async () => { await mqttClient.ConnectAsync(option()); });

            }
        }

        private async void timer2_TickAsync(object sender, EventArgs e)
        {
            if (mqttClient == null)
            {
                timer2.Enabled = false;
                MessageBox.Show("设备未连接！");
              
                return;
            }
            if (mqttClient.IsConnected)
            {
                await Publish();
                label6.Visible = false;
                cmbPubQOS.Visible = false;
            }
            else
            {
                timer2.Enabled = false;
                MessageBox.Show("设备未连接");
                return;
            }
           
        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer2.Enabled = false;
        }

        private void btnsend_Click(object sender, EventArgs e)
        {
            totalcount = 0;
            tbsendnum.Text = "发送：" + totalcount;
        }

        private void btnrecv_Click(object sender, EventArgs e)
        {
            recvcount = 0;
            tbrecvnum.Text = "接收：" + recvcount;
        }
    }
}
